/**
 * @file reqrep_client.c
 * @brief nanomsg REQ/REP 模式客户端演示
 * 
 * 这个示例展示了如何使用 nanomsg 的 REQ (Request) 模式实现客户端。
 * 客户端发送请求到服务器并等待响应。
 */

#include "common.h"

// 全局变量
volatile int g_running = 1;
stats_t g_stats = {0};

/**
 * @brief 生成测试请求
 * @param request_type 请求类型
 * @param sequence 序列号
 * @param buffer 输出缓冲区
 * @param buffer_size 缓冲区大小
 * @return 生成的数据长度
 */
int generate_request(message_type_t request_type, int sequence, char* buffer, size_t buffer_size) {
    switch (request_type) {
        case MSG_TEXT:
            return snprintf(buffer, buffer_size, "Hello from client, request #%d", sequence);
            
        case MSG_JSON:
            return snprintf(buffer, buffer_size, 
                           "{\"type\":\"request\",\"seq\":%d,\"data\":\"test_data_%d\",\"timestamp\":%u}", 
                           sequence, sequence, get_timestamp());
            
        case MSG_HEARTBEAT:
            return snprintf(buffer, buffer_size, "HEARTBEAT");
            
        default:
            return snprintf(buffer, buffer_size, "UNKNOWN_REQUEST_TYPE");
    }
}

/**
 * @brief 运行单次请求-响应
 * @param sock 套接字
 * @param request_type 请求类型
 * @param sequence 序列号
 * @return 成功返回0，失败返回-1
 */
int send_single_request(int sock, message_type_t request_type, int sequence) {
    char request_data[BUFFER_SIZE];
    char send_buffer[MAX_MESSAGE_SIZE];
    char recv_buffer[MAX_MESSAGE_SIZE];
    
    // 生成请求数据
    int data_len = generate_request(request_type, sequence, request_data, sizeof(request_data));
    if (data_len <= 0) {
        log_message(LOG_ERROR, "Failed to generate request");
        return -1;
    }
    
    // 创建请求消息
    message_t* request = create_message(request_type, request_data, data_len);
    if (!request) {
        log_message(LOG_ERROR, "Failed to create request message");
        return -1;
    }
    
    // 序列化请求
    int serialized_len = serialize_message(request, send_buffer, sizeof(send_buffer));
    if (serialized_len <= 0) {
        log_message(LOG_ERROR, "Failed to serialize request");
        destroy_message(request);
        return -1;
    }
    
    log_message(LOG_INFO, "Sending request [seq:%u]: %s", request->sequence, request_data);
    
    // 发送请求
    int bytes_sent = nn_send(sock, send_buffer, serialized_len, 0);
    if (bytes_sent < 0) {
        log_message(LOG_ERROR, "Failed to send request: %s", nn_strerror(nn_errno()));
        destroy_message(request);
        update_error_stats();
        return -1;
    }
    
    update_send_stats(bytes_sent);
    log_message(LOG_DEBUG, "Request sent: %d bytes", bytes_sent);
    
    // 接收响应
    int bytes_received = nn_recv(sock, recv_buffer, sizeof(recv_buffer), 0);
    if (bytes_received < 0) {
        log_message(LOG_ERROR, "Failed to receive response: %s", nn_strerror(nn_errno()));
        destroy_message(request);
        update_error_stats();
        return -1;
    }
    
    update_recv_stats(bytes_received);
    
    // 反序列化响应
    message_t* response = deserialize_message(recv_buffer, bytes_received);
    if (response) {
        log_message(LOG_INFO, "Received response [seq:%u]: %s", 
                   response->sequence, response->data);
        destroy_message(response);
    } else {
        log_message(LOG_WARN, "Failed to deserialize response, raw data: %.*s", 
                   bytes_received, recv_buffer);
    }
    
    destroy_message(request);
    return 0;
}

/**
 * @brief 运行批量请求测试
 * @param sock 套接字
 * @param count 请求数量
 * @param interval 请求间隔（毫秒）
 * @return 成功返回0，失败返回-1
 */
int run_batch_requests(int sock, int count, int interval) {
    log_message(LOG_INFO, "Starting batch test: %d requests with %d ms interval", count, interval);
    
    message_type_t request_types[] = {MSG_TEXT, MSG_JSON, MSG_HEARTBEAT};
    int type_count = sizeof(request_types) / sizeof(request_types[0]);
    
    for (int i = 1; i <= count && should_continue(); i++) {
        message_type_t type = request_types[i % type_count];
        
        if (send_single_request(sock, type, i) != 0) {
            log_message(LOG_ERROR, "Request %d failed", i);
            continue;
        }
        
        // 间隔控制
        if (interval > 0 && i < count) {
            usleep(interval * 1000); // 转换为微秒
        }
        
        // 进度报告
        if (i % 10 == 0) {
            log_message(LOG_INFO, "Progress: %d/%d requests completed", i, count);
        }
    }
    
    return 0;
}

/**
 * @brief 运行性能测试
 * @param sock 套接字
 * @param duration 测试持续时间（秒）
 * @return 成功返回0，失败返回-1
 */
int run_performance_test(int sock, int duration) {
    log_message(LOG_INFO, "Starting performance test for %d seconds", duration);
    
    time_t start_time = time(NULL);
    time_t end_time = start_time + duration;
    int sequence = 0;
    
    while (time(NULL) < end_time && should_continue()) {
        if (send_single_request(sock, MSG_TEXT, ++sequence) != 0) {
            log_message(LOG_WARN, "Performance test request failed");
        }
    }
    
    time_t actual_duration = time(NULL) - start_time;
    log_message(LOG_INFO, "Performance test completed in %ld seconds", actual_duration);
    
    return 0;
}

/**
 * @brief 运行交互式模式
 * @param sock 套接字
 * @return 成功返回0，失败返回-1
 */
int run_interactive_mode(int sock) {
    char input[BUFFER_SIZE];
    int sequence = 0;
    
    log_message(LOG_INFO, "Interactive mode started. Type 'quit' to exit.");
    printf("Commands:\n");
    printf("  text <message>    - Send text message\n");
    printf("  json <data>       - Send JSON message\n");
    printf("  heartbeat         - Send heartbeat\n");
    printf("  quit              - Exit interactive mode\n");
    printf("\n");
    
    while (should_continue()) {
        printf("client> ");
        fflush(stdout);
        
        if (!fgets(input, sizeof(input), stdin)) {
            break;
        }
        
        // 移除换行符
        input[strcspn(input, "\n")] = 0;
        
        if (strcmp(input, "quit") == 0) {
            break;
        } else if (strncmp(input, "text ", 5) == 0) {
            char* message = input + 5;
            message_t* msg = create_message(MSG_TEXT, message, strlen(message));
            if (msg) {
                char buffer[MAX_MESSAGE_SIZE];
                int len = serialize_message(msg, buffer, sizeof(buffer));
                if (len > 0) {
                    nn_send(sock, buffer, len, 0);
                    update_send_stats(len);
                    log_message(LOG_INFO, "Sent: %s", message);
                }
                destroy_message(msg);
            }
        } else if (strncmp(input, "json ", 5) == 0) {
            char* data = input + 5;
            char json_msg[BUFFER_SIZE];
            snprintf(json_msg, sizeof(json_msg), "{\"data\":\"%s\",\"seq\":%d}", data, ++sequence);
            message_t* msg = create_message(MSG_JSON, json_msg, strlen(json_msg));
            if (msg) {
                char buffer[MAX_MESSAGE_SIZE];
                int len = serialize_message(msg, buffer, sizeof(buffer));
                if (len > 0) {
                    nn_send(sock, buffer, len, 0);
                    update_send_stats(len);
                    log_message(LOG_INFO, "Sent JSON: %s", json_msg);
                }
                destroy_message(msg);
            }
        } else if (strcmp(input, "heartbeat") == 0) {
            message_t* msg = create_message(MSG_HEARTBEAT, "HEARTBEAT", 9);
            if (msg) {
                char buffer[MAX_MESSAGE_SIZE];
                int len = serialize_message(msg, buffer, sizeof(buffer));
                if (len > 0) {
                    nn_send(sock, buffer, len, 0);
                    update_send_stats(len);
                    log_message(LOG_INFO, "Sent heartbeat");
                }
                destroy_message(msg);
            }
        } else {
            printf("Unknown command: %s\n", input);
            continue;
        }
        
        // 接收响应
        char recv_buffer[MAX_MESSAGE_SIZE];
        int bytes_received = nn_recv(sock, recv_buffer, sizeof(recv_buffer), 0);
        if (bytes_received > 0) {
            update_recv_stats(bytes_received);
            message_t* response = deserialize_message(recv_buffer, bytes_received);
            if (response) {
                printf("Response: %s\n", response->data);
                destroy_message(response);
            }
        } else {
            log_message(LOG_ERROR, "Failed to receive response: %s", nn_strerror(nn_errno()));
        }
    }
    
    return 0;
}

/**
 * @brief 打印使用说明
 */
void print_client_usage(const char* program_name) {
    printf("Usage: %s [options] [mode]\n", program_name);
    printf("\n");
    printf("Modes:\n");
    printf("  single             Single request (default)\n");
    printf("  batch COUNT        Send COUNT requests\n");
    printf("  perf DURATION      Performance test for DURATION seconds\n");
    printf("  interactive        Interactive mode\n");
    printf("\n");
    printf("Options:\n");
    printf("  -h, --help         Show this help message\n");
    printf("  -v, --version      Show version information\n");
    printf("  -a, --address ADDR Server address (default: %s)\n", DEFAULT_TCP_ADDR);
    printf("  -t, --timeout MS   Request timeout in milliseconds (default: 5000)\n");
    printf("  -i, --interval MS  Interval between requests in batch mode (default: 1000)\n");
    printf("  -r, --retries NUM  Number of retries on failure (default: 3)\n");
    printf("\n");
    printf("Examples:\n");
    printf("  %s                              # Single request\n", program_name);
    printf("  %s batch 100                    # Send 100 requests\n", program_name);
    printf("  %s perf 30                      # 30-second performance test\n", program_name);
    printf("  %s interactive                  # Interactive mode\n", program_name);
    printf("  %s -a tcp://server:8080 batch 50  # Custom server and batch test\n", program_name);
}

/**
 * @brief 主函数
 */
int main(int argc, char* argv[]) {
    const char* address = DEFAULT_TCP_ADDR;
    int timeout = 5000;
    int interval = 1000;
    int retries = 3;
    const char* mode = "single";
    int mode_param = 1;
    
    // 解析命令行参数
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
            print_client_usage(argv[0]);
            return 0;
        } else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
            print_nanomsg_info();
            return 0;
        } else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--address") == 0) {
            if (i + 1 < argc) {
                address = argv[++i];
            }
        } else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--timeout") == 0) {
            if (i + 1 < argc) {
                timeout = atoi(argv[++i]);
            }
        } else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--interval") == 0) {
            if (i + 1 < argc) {
                interval = atoi(argv[++i]);
            }
        } else if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--retries") == 0) {
            if (i + 1 < argc) {
                retries = atoi(argv[++i]);
            }
        } else if (strcmp(argv[i], "single") == 0) {
            mode = "single";
        } else if (strcmp(argv[i], "batch") == 0) {
            mode = "batch";
            if (i + 1 < argc) {
                mode_param = atoi(argv[++i]);
            }
        } else if (strcmp(argv[i], "perf") == 0) {
            mode = "perf";
            if (i + 1 < argc) {
                mode_param = atoi(argv[++i]);
            }
        } else if (strcmp(argv[i], "interactive") == 0) {
            mode = "interactive";
        }
    }
    
    // 初始化
    setup_signal_handlers();
    init_stats();
    check_nanomsg_version();
    
    log_message(LOG_INFO, "=== Nanomsg REQ Client Demo ===");
    log_message(LOG_INFO, "Server: %s (%s)", address, parse_address_type(address));
    log_message(LOG_INFO, "Mode: %s", mode);
    log_message(LOG_INFO, "Timeout: %d ms", timeout);
    
    // 创建 REQ 套接字
    int sock = nn_socket(AF_SP, NN_REQ);
    CHECK_SOCKET(sock);
    
    // 设置超时
    if (nn_setsockopt(sock, NN_SOL_SOCKET, NN_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
        log_message(LOG_WARN, "Failed to set receive timeout");
    }
    if (nn_setsockopt(sock, NN_SOL_SOCKET, NN_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
        log_message(LOG_WARN, "Failed to set send timeout");
    }
    
    // 连接到服务器
    int connect_result = nn_connect(sock, address);
    CHECK_CONNECT(connect_result, address);
    
    log_message(LOG_INFO, "Connected to server, starting %s mode...", mode);
    
    int result = 0;
    
    // 根据模式运行
    if (strcmp(mode, "single") == 0) {
        result = send_single_request(sock, MSG_TEXT, 1);
    } else if (strcmp(mode, "batch") == 0) {
        result = run_batch_requests(sock, mode_param, interval);
    } else if (strcmp(mode, "perf") == 0) {
        result = run_performance_test(sock, mode_param);
    } else if (strcmp(mode, "interactive") == 0) {
        result = run_interactive_mode(sock);
    }
    
    nn_close(sock);
    
    // 打印统计信息
    log_message(LOG_INFO, "Client finished");
    print_stats();
    
    return result;
}

// 实现必要的公共函数（基础版本）
#include <stdarg.h>

void init_stats(void) {
    memset(&g_stats, 0, sizeof(g_stats));
    g_stats.start_time = time(NULL);
}

void print_stats(void) {
    time_t duration = time(NULL) - g_stats.start_time;
    printf("\n" COLOR_CYAN "=== Client Statistics ===" COLOR_RESET "\n");
    printf("Duration: %ld seconds\n", duration);
    printf("Requests sent: %lu\n", g_stats.messages_sent);
    printf("Responses received: %lu\n", g_stats.messages_received);
    printf("Bytes sent: %lu\n", g_stats.bytes_sent);
    printf("Bytes received: %lu\n", g_stats.bytes_received);
    printf("Errors: %u\n", g_stats.errors);
    if (duration > 0) {
        printf("Request rate: %.2f req/s\n", (double)g_stats.messages_sent / duration);
        printf("Success rate: %.2f%%\n", 
               g_stats.messages_sent > 0 ? 
               (double)g_stats.messages_received / g_stats.messages_sent * 100 : 0);
    }
}

void log_message(log_level_t level, const char* format, ...) {
    const char* level_colors[] = {COLOR_BLUE, COLOR_GREEN, COLOR_YELLOW, COLOR_RED};
    const char* level_names[] = {"DEBUG", "INFO", "WARN", "ERROR"};
    
    char timestamp[32];
    time_t now = time(NULL);
    struct tm* tm_info = localtime(&now);
    strftime(timestamp, sizeof(timestamp), "%H:%M:%S", tm_info);
    
    va_list args;
    va_start(args, format);
    
    printf("%s[%s] %s%s" COLOR_RESET " ", 
           level_colors[level], timestamp, level_names[level], COLOR_RESET);
    vprintf(format, args);
    printf("\n");
    
    va_end(args);
    fflush(stdout);
}

void handle_error(const char* message) {
    log_message(LOG_ERROR, "%s: %s", message, nn_strerror(nn_errno()));
    update_error_stats();
}

void signal_handler(int sig) {
    if (sig == SIGINT || sig == SIGTERM) {
        log_message(LOG_INFO, "Received signal %d, shutting down...", sig);
        g_running = 0;
    }
}

void setup_signal_handlers(void) {
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
}

message_t* create_message(message_type_t type, const char* data, uint32_t length) {
    static uint32_t sequence = 0;
    message_t* msg = malloc(sizeof(message_t));
    if (!msg) return NULL;
    
    msg->type = type;
    msg->sequence = ++sequence;
    msg->timestamp = get_timestamp();
    msg->data_length = length;
    
    if (length > 0 && data) {
        memcpy(msg->data, data, length);
    }
    
    return msg;
}

void destroy_message(message_t* msg) {
    if (msg) free(msg);
}

int serialize_message(const message_t* msg, char* buffer, size_t buffer_size) {
    if (!msg || !buffer) return -1;
    
    size_t total_size = sizeof(message_type_t) + sizeof(uint32_t) * 3 + msg->data_length;
    if (total_size > buffer_size) return -1;
    
    char* ptr = buffer;
    memcpy(ptr, &msg->type, sizeof(msg->type)); ptr += sizeof(msg->type);
    memcpy(ptr, &msg->sequence, sizeof(msg->sequence)); ptr += sizeof(msg->sequence);
    memcpy(ptr, &msg->timestamp, sizeof(msg->timestamp)); ptr += sizeof(msg->timestamp);
    memcpy(ptr, &msg->data_length, sizeof(msg->data_length)); ptr += sizeof(msg->data_length);
    memcpy(ptr, msg->data, msg->data_length);
    
    return total_size;
}

message_t* deserialize_message(const char* buffer, size_t length) {
    if (!buffer || length < sizeof(message_type_t) + sizeof(uint32_t) * 3) return NULL;
    
    message_t* msg = malloc(sizeof(message_t));
    if (!msg) return NULL;
    
    const char* ptr = buffer;
    memcpy(&msg->type, ptr, sizeof(msg->type)); ptr += sizeof(msg->type);
    memcpy(&msg->sequence, ptr, sizeof(msg->sequence)); ptr += sizeof(msg->sequence);
    memcpy(&msg->timestamp, ptr, sizeof(msg->timestamp)); ptr += sizeof(msg->timestamp);
    memcpy(&msg->data_length, ptr, sizeof(msg->data_length)); ptr += sizeof(msg->data_length);
    
    if (msg->data_length > MAX_MESSAGE_SIZE || 
        length < sizeof(message_type_t) + sizeof(uint32_t) * 3 + msg->data_length) {
        free(msg);
        return NULL;
    }
    
    memcpy(msg->data, ptr, msg->data_length);
    return msg;
}

uint32_t get_timestamp(void) {
    return (uint32_t)time(NULL);
}

const char* parse_address_type(const char* addr) {
    if (strncmp(addr, "tcp://", 6) == 0) return "TCP";
    if (strncmp(addr, "ipc://", 6) == 0) return "IPC";
    if (strncmp(addr, "inproc://", 9) == 0) return "INPROC";
    return "UNKNOWN";
}

void check_nanomsg_version(void) {
    log_message(LOG_INFO, "Nanomsg REQ client initialized");
}

void print_nanomsg_info(void) {
    printf("Nanomsg REQ/REP Client Demo v1.0\n");
    printf("Built with nanomsg library\n");
    printf("Features: Batch testing, Performance testing, Interactive mode\n");
}